package com.moonLight.weblog.web.service.Impl;

import com.moonLight.weblog.common.domain.dos.UserDo;
import com.moonLight.weblog.common.domain.mapper.BlogSettingsMapper;
import com.moonLight.weblog.common.domain.mapper.UserMapper;
import com.moonLight.weblog.common.enums.ResponseCodeEnum;
import com.moonLight.weblog.common.exception.BizException;
import com.moonLight.weblog.common.mail.MailHelper;
import com.moonLight.weblog.common.utils.Response;
import com.moonLight.weblog.web.model.vo.user.UpdateUserPasswordReqVO;
import com.moonLight.weblog.web.model.vo.user.UserPasswordReqVO;
import com.moonLight.weblog.web.service.UserService;
import io.jsonwebtoken.io.SerializationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserServiceImpl implements UserService {
    /**
     * 修改密码
     * 1.系统自动根据数据库中的 邮箱对用户发送验证码 生成的验证码 保存到redis中 限时两分钟
     * 2.用户输入验证码
     * 3.用户输入新密码
     * 4.修改成功
     */

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private MailHelper mailHelper;
    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public Response getCode(UserPasswordReqVO updateUserPasswordReqVO) {
        String username = updateUserPasswordReqVO.getUsername();
        String email = updateUserPasswordReqVO.getEmail();
        UserDo userDetail = null;

        // 参数校验逻辑
        if (email == null || email.isEmpty()) {
            log.warn("==> 邮箱不能为空");
            throw new BizException(ResponseCodeEnum.USER_EMAIL_NOT_MATCH);
        }else{

        }

        // 优先根据邮箱查找用户
        userDetail = userMapper.findByEmail(email);
        if (userDetail == null) {
            log.warn("==> 未找到该邮箱对应的用户, email: {}", email);
            throw new BizException(ResponseCodeEnum.USERNAME_NOT_FOUND);
        }

        // 如果提供了用户名，则进行匹配校验
        if (username != null && !username.isEmpty()) {
            if (!username.equals(userDetail.getUsername())) {
                log.warn("==> 用户名不匹配, 提供的username: {}, 数据库中的username: {}", username, userDetail.getUsername());
                throw new BizException(ResponseCodeEnum.USER_EMAIL_NOT_MATCH);
            }
        } else {
            // 如果未提供用户名，则使用数据库中查到的用户名
            username = userDetail.getUsername();
        }

        // 校验用户是否绑定了邮箱
        if (userDetail.getEmail() == null || userDetail.getEmail().isEmpty()) {
            log.warn("==> 该用户没有绑定邮箱, username: {}", username);
            throw new BizException(ResponseCodeEnum.USER_EMAIL_NOT_MATCH);
        }

        // 校验邮箱是否匹配
        if (!email.equals(userDetail.getEmail())) {
            log.warn("==> 该用户邮箱不匹配, username: {}", username);
            throw new BizException(ResponseCodeEnum.USER_EMAIL_NOT_MATCH);
        }




        String redisUserName = username + "/" +email;

        // 检查是否已存在有效的验证码
        try {
            Object existingCode = redisTemplate.opsForValue().get(redisUserName);
            if (existingCode != null) {
                log.warn("==> 验证码已存在，请勿重复发送, redis_id: {}", redisUserName);
                throw new BizException(ResponseCodeEnum.VERIFICATION_CODE_REPEAT);
            }
        } catch (Exception e) {
            log.warn("==> 检查验证码存在性时发生异常, redis_id: {}", redisUserName, e);
        }

        String uuid = UUID.randomUUID().toString().replace("-", "");
        String verificationCode = uuid.substring(0, 6).toUpperCase();
        log.info("==> 验证码：{}", verificationCode);

        try {
            redisTemplate.opsForValue().set(redisUserName, verificationCode, 120, TimeUnit.SECONDS);
            // 验证是否保存成功
            Object savedCode = redisTemplate.opsForValue().get(redisUserName);
            if (savedCode != null) {
                log.info("==> 验证码在redis中保存成功，验证通过");
            } else {
                log.warn("==> 验证码在redis中保存失败，无法读取");
            }
        } catch (Exception e) {
            log.warn("==> 验证码在redis保存失败，redis_id: {}", redisUserName, e);
            throw new BizException(ResponseCodeEnum.VERIFICATION_CODE_SAVE_FAILED);
        }

        boolean sendResult  = mailHelper.sendMail(email, "个人博客修改密码", "验证码：" + verificationCode);
        if (!sendResult){
            log.warn("==> 邮件发送失败");
            throw new BizException(ResponseCodeEnum.EMAIL_SEND_FAILED);
        }
        return Response.success();
    }

    @Override
    public Response updatePassword(UpdateUserPasswordReqVO updateUserPasswordReqVO) {
        String username = updateUserPasswordReqVO.getUsername();
        String email = updateUserPasswordReqVO.getEmail();
        String code = updateUserPasswordReqVO.getCode();
        String newPassword = updateUserPasswordReqVO.getNewPassword();
        String redisUserName = username + "/" + email;
        try {
            Object redisCodeObj = redisTemplate.opsForValue().get(redisUserName);
            String redisCode = null;
            if (redisCodeObj instanceof String) {
                redisCode = (String) redisCodeObj;
            }
            if (redisCode == null){
                log.warn("==> 验证码在redis中不存在, redis_id: {}", redisUserName);
                throw new BizException(ResponseCodeEnum.VERIFICATION_CODE_EXPIRED);
            }
            if (!code.equals(redisCode)){
                log.warn("==> 验证码不匹配, redis_id: {}", redisUserName);
                throw new BizException(ResponseCodeEnum.VERIFICATION_CODE_ERROR);
            }
        }
        catch (Exception e) {
            if (e instanceof SerializationException){
                log.warn("Redis数据序列化异常，key: {}", redisUserName, e);
                redisTemplate.delete(redisUserName);
            }
        }

        // 获取用户当前密码
        String oldPassword = userMapper.findByEmail(email).getPassword();
        // 对新密码进行加密
        String encodedNewPassword = passwordEncoder.encode(newPassword);
        log.info("==> 密码加密：{}", encodedNewPassword);

        // 验证新旧密码是否相同（使用matches方法比较明文和加密密码）
        boolean matches = passwordEncoder.matches(newPassword, oldPassword);
        // 新旧密码不能相同
        if (matches) {
            log.warn("==> 新密码不能与旧密码相同, username: {}", username);
            throw new BizException(ResponseCodeEnum.NEW_PASSWORD_NOT_MATCH);
        }

        int count = userMapper.updatePasswordByUsername(username, encodedNewPassword);
        if (count == 0) {
            log.warn("==> 密码修改失败, username: {}", username);
            throw new BizException(ResponseCodeEnum.UPDATE_PASSWORD_FAILED);
        }
        return Response.success();
    }
}
